package gamelogic

import (
	"server_cluster/common/config"
	"server_cluster/common/gdconf"
	"server_cluster/common/logger"
	"server_cluster/common/mysock"
	"server_cluster/common/protoc/pb"
	"server_cluster/common/tools"
	"server_cluster/http/pkg/random"
	"server_cluster/logic/sharemem"
)

func fishWeightUp(effect gdconf.IntArray, fishPool gdconf.IdWeightList) {
	switch effect[0] {
	case gdconf.FishWeightUpTypeRarity:
		for _, idWeight := range fishPool {
			fishConfig := gdconf.GetFishConfig(idWeight.Id)
			if fishConfig == nil {
				continue
			}
			if fishConfig.Rarity == effect[1] {
				idWeight.Weight += effect[2]
			}
		}
	case gdconf.FishWeightUpTypeId:
		for _, idWeight := range fishPool {
			if idWeight.Id == effect[1] {
				idWeight.Weight += effect[2]
			}
		}
	}
}

func UserTeleport(user *sharemem.User, sceneId, sceneTag int32, buf *mysock.SockBuf) {
	resp := pb.SC_EnterSceneResp{}
	resp.CurSceneId = user.SceneId
	resp.RetCode = config.OK
	resp.TargetSceneId = sceneId
	var scene = user.GetSceneById(sceneId)
	if scene == nil {
		logger.Error("scene not exist, SceneId: %v", sceneId)
		resp.RetCode = config.OBJECT_NOT_FOUND
		SendMsg(config.SC_EnterSceneResp, &resp, buf, user)
		return
	}
	if sceneTag != -1 {
		scene.SetSceneTag(int8(sceneTag))
	}
	TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_ENTER_SCENE, true, scene.SceneId)
	if user.SceneId != scene.SceneId {
		scene.RefreshMonster(user)
		user.SetSceneId(scene.SceneId)
		for _, role := range user.GetRoleMap() {
			role.CurrEnergy = 0
			role.CurrHp = user.GetUserRoleFightProp(role.GetId())[config.FIGHT_PROP_HP]
			role.SetSync()
		}
	}
	resp.SceneTag = int32(scene.SceneTag)
	scene.PacketGadgetMap(&resp.EntityList, user)
	scene.PacketMonsterMap(&resp.EntityList, user)
	scene.PacketNpcMap(&resp.EntityList, user)
	gdconf.PacketFishPointBySceneId(sceneId, &resp.EntityList)
	TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_GADGET_STATE, true)
	SendMsg(config.SC_EnterSceneResp, &resp, buf, user)
}

func AddUserScene(sceneId int32, user *sharemem.User) {
	ok := user.AddScene(sceneId)
	if !ok {
		logger.Error("add u scene fail, uid: %v", user.GetUid())
		return
	}
	SendMsg(config.SC_SceneUnlockNtf, &pb.SC_SceneUnlockNtf{UnlockSceneId: sceneId}, nil, user)
}
func TriggerUnlockMonster(user *sharemem.User, cond int32, param ...int32) {
	logger.Debug("[TriggerUnlockMonster] cond: %v, param: %v, uid: %v", cond, param, user.GetUid())
	for _, scene := range user.GetSceneMap() {
		sceneData := gdconf.GetSceneData(scene.SceneId)
		if sceneData == nil {
			continue
		}
		for _, monster := range sceneData.MonsterList {
			battleGroupConfig := gdconf.GetBattleGroupConfig(monster.MonsterId)
			if battleGroupConfig == nil {
				continue
			}
			if battleGroupConfig.UnlockCond == nil {
				continue
			}
			if battleGroupConfig.UnlockCond[0] != cond {
				continue
			}
			switch cond {
			case gdconf.BattleGroupUnlockCondTypeFinishQuest:
				questId := param[0]
				if battleGroupConfig.UnlockCond[1] != questId {
					continue
				}
			default:
				continue
			}
			logger.Debug("[UnlockMonster] MonsterId: %v, SceneId: %v, uid: %v", monster.MonsterId, scene.SceneId, user.GetUid())
			scene.AddMonster(monster.MonsterId, user)
			if user.SceneId == scene.SceneId {
				dbMonster := user.GetSceneMonsterById(scene.SceneId, monster.MonsterId)
				if dbMonster != nil {
					UserSceneMonsterNotify(user, scene, dbMonster)
				}
			}
		}
	}
}

func TriggerAppearNpc(user *sharemem.User, cond int32, isNeedNotify bool, param ...int32) {
	logger.Debug("[TriggerAppearNpc] cond: %v, param: %v, uid: %v", cond, param, user.GetUid())
	for _, scene := range user.GetSceneMap() {
		for _, npc := range user.GetSceneNpcMap(scene.SceneId) {
			npcConfig := gdconf.GetNpcConfig(npc.Id)
			if npcConfig == nil {
				continue
			}
			for _, appearCond := range npcConfig.AppearCondList {
				if appearCond[0] != cond {
					continue
				}
				switch cond {
				case gdconf.AppearCondAcceptQuestAppear:
					questId := param[0]
					if appearCond[1] != questId {
						continue
					}
					npc.Appear = true
				case gdconf.AppearCondFinishQuestAppear:
					questId := param[0]
					if appearCond[1] != questId {
						continue
					}
					npc.Appear = true
				case gdconf.AppearCondFinishQuestDisappear:
					questId := param[0]
					if appearCond[1] != questId {
						continue
					}
					npc.Appear = false
				default:
					continue
				}
				if user.SceneId == scene.SceneId && isNeedNotify {
					UserSceneNpcNotify(user, scene, npc)
				}
			}

		}
	}
}

func TriggerUnlockBox(user *sharemem.User, cond int32, isNeedNotify bool, param ...int32) {
	logger.Debug("[TriggerUnlockBox] cond: %v, param: %v, uid: %v", cond, param, user.GetUid())
	for _, scene := range user.GetSceneMap() {
		for _, gadget := range user.GetSceneGadgetMap(scene.SceneId) {
			if gadget.GadgetState == int8(pb.GadgetState_GADGET_STATE_OPEN) {
				continue
			}
			var gadgetConfigId int32
			if pb.GadgetType(gadget.GadgetType) == pb.GadgetType_GADGET_TYPE_CHEST {
				gadgetConfigId = gadget.Id
			} else {
				gadgetConfigId = gadget.Id + scene.SceneId*1000
			}
			boxConfig := gdconf.GetGadgetActiveConfig(gadgetConfigId)
			if boxConfig == nil {
				continue
			}
			if boxConfig.UnlockCond == nil {
				continue
			}

			if boxConfig.UnlockCond[0] != cond {
				continue
			}
			switch cond {
			case gdconf.GadgetUnlockCondAcceptParentQuest:
				parentQuestId := param[0]
				if boxConfig.UnlockCond[1] != parentQuestId {
					return
				}
			case gdconf.GadgetUnlockCondFinishParentQuest:
				parentQuestId := param[0]
				if boxConfig.UnlockCond[1] != parentQuestId {
					return
				}
			case gdconf.GadgetUnlockCondFinishFight:
				battleGroupId := param[0]
				if boxConfig.UnlockCond[1] != battleGroupId {
					return
				}
			case gdconf.GadgetUnlockCondGiveItem:
			case gdconf.GadgetUnlockCondByOtherGadget:
				var isUnlock = true
				for _, id := range boxConfig.UnlockCond[1:] {
					var sceneId, gadgetId = id / 1000, id % 1000
					var targetScene = user.GetSceneById(sceneId)
					if targetScene == nil {
						isUnlock = false
						continue
					}
					targetGadget := user.GetSceneGadgetById(targetScene.SceneId, gadgetId)
					if targetGadget == nil {
						isUnlock = false
						continue
					}
					if targetGadget.GadgetState != int8(pb.GadgetState_GADGET_STATE_OPEN) {
						isUnlock = false
						continue
					}
				}
				if !isUnlock {
					continue
				}
			case gdconf.GadgetUnlockCondAcceptSubQuest:
				subQuestId := param[0]
				if boxConfig.UnlockCond[1] != subQuestId {
					continue
				}
			case gdconf.GadgetUnlockCondFinishSubQuest:
				subQuestId := param[0]
				if boxConfig.UnlockCond[1] != subQuestId {
					continue
				}
			default:
				return
			}
			logger.Debug("[UnlockBox] GadgetId: %v, SceneId: %v, uid: %v", gadget.Id, scene.SceneId, user.GetUid())
			var oldState = gadget.GadgetState
			gadget.GadgetState = int8(pb.GadgetState_GADGET_STATE_OPEN)
			if user.SceneId == scene.SceneId && isNeedNotify {
				UserSceneGadgetNotify(user, scene, gadget)
			}
			if oldState != gadget.GadgetState {
				TriggerUnlockBox(user, gdconf.GadgetUnlockCondByOtherGadget, true, 0)
				TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_SCENE_INTERACT, true, scene.SceneId, gadget.Id)
				TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_GADGET_STATE, true)
			}

		}
	}
}

// SceneFightFinish 完成场景战斗
func SceneFightFinish(battleGroupId int32, user *sharemem.User) (int32, bool) {
	logger.Info("[MarkPlayerAction SceneFightFinish %v %v]", battleGroupId, user.GetUid())
	logger.Debug("[SceneFightFinish] battleGroupId: %v, uid: %v", battleGroupId, user.GetUid())
	TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_FINISH_FIGHT, true, battleGroupId)
	TriggerUnlockBox(user, gdconf.GadgetUnlockCondFinishFight, true, battleGroupId)
	user.TriggerActivityTask(gdconf.ActivityTaskFinishCondFinishFight)
	battleGroupConfig := gdconf.GetBattleGroupConfig(battleGroupId)
	if battleGroupConfig == nil {
		return config.CONFIG_NOT_FOUND, false
	}
	switch battleGroupConfig.Type {
	case gdconf.BattleGroupTypeSceneMonster:
		// 场景战斗验证
		var scene = user.GetSceneById(user.SceneId)
		if scene == nil {
			logger.Error("scene not exist, sceneId: %v, uid: %v", user.SceneId, user.GetUid())
			return config.OBJECT_NOT_FOUND, false
		}
		var monster = user.GetSceneMonsterById(scene.SceneId, battleGroupId)
		if monster == nil {
			logger.Error("monster not exist, sceneId: %v, battleGroupId: %v, uid: %v", user.SceneId, battleGroupId, user.GetUid())
			return config.OBJECT_NOT_FOUND, false
		}
		if !monster.Appear {
			logger.Debug("scene fight state is hide, sceneId: %v, battleGroupId: %v, uid: %v", user.SceneId, battleGroupId, user.GetUid())
			return config.SERVER_ERROR, false
		}
		monster.Appear = false
		firstKill := false
		if !monster.FirstKillDone {
			monster.FirstKillDone = true
			firstKill = true
		}
		UserSceneMonsterNotify(user, scene, monster)
		return config.OK, firstKill
	case gdconf.BattleGroupTypeDungeon:
		// 地牢解锁
		var firstKill = false
		for _, dungeonConfig := range gdconf.GetDungeonConfigMap() {
			if dungeonConfig.BattleGroupId == battleGroupId {
				dungeonActivity := user.GetDungeonActivity(dungeonConfig.ActivityId)
				if dungeonActivity == nil {
					logger.Error("获取地牢活动对象失败 %v", dungeonConfig.ActivityId)
					continue
				}
				costItemMap := map[int32]int32{dungeonConfig.EnterCostItemId: dungeonConfig.EnterCostItemCount}
				ok := CostItems(costItemMap, user)
				if !ok {
					logger.Error("道具不足 %v", costItemMap)
					return config.SERVER_ERROR, false
				}
				if dungeonActivity.PassDungeonId < dungeonConfig.DungeonId {
					firstKill = true
					dungeonActivity.PassDungeonId = dungeonConfig.DungeonId
				}
				TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_ACTIVITY_DUNGEON, true, dungeonConfig.ActivityId, dungeonConfig.DungeonId)
				TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_ACTIVITY_DUNGEON_COUNT, true, dungeonConfig.ActivityId, 1)
				user.TriggerActivityTask(gdconf.ActivityTaskFinishCondAnyDungeon, dungeonConfig.ActivityId, 1)
				user.TriggerActivityTask(gdconf.ActivityTaskFinishCondFinishActivityDungeon, dungeonConfig.ActivityId, 1)
				logger.Info("dungeon pass, DungeonId: %v", dungeonConfig.DungeonId)
				break
			}
		}
		return config.OK, firstKill
	case gdconf.BattleGroupTypeTower:
		// 爬塔通关
		for _, towerConfig := range gdconf.GetTowerConfigMap() {
			if towerConfig.BattleGroupId == battleGroupId {
				user.UserActivity.SetTowerRecord(towerConfig)
				TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_ACTIVITY_DUNGEON, true, towerConfig.ActivityId, towerConfig.TowerId)
				TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_ACTIVITY_DUNGEON_COUNT, true, towerConfig.ActivityId, 1)
				logger.Info("tower pass, Area: %v, Level: %v", towerConfig.Area, towerConfig.Level)
				break
			}
		}
		var towerAreaNextLevel *gdconf.TowerConfig = nil
		for _, towerConfig := range gdconf.GetTowerConfigMap() {
			if towerConfig.Area == user.UserActivity.TowerArea && towerConfig.Level == user.UserActivity.TowerLevel+1 {
				towerAreaNextLevel = towerConfig
			}
		}
		var towerNextArea *gdconf.TowerConfig = nil
		for _, towerConfig := range gdconf.GetTowerConfigMap() {
			if towerConfig.Area == user.UserActivity.TowerArea+1 {
				towerNextArea = towerConfig
			}
		}
		if towerNextArea != nil && towerAreaNextLevel == nil {
			user.UserActivity.UpdateTowerRecord()
		}
		user.UserActivity.SetTowerPassTime(sharemem.MyShm.TimeNow)
		return config.OK, true
	default:
		return config.OK, false
	}
}

func UserSceneMonsterNotify(user *sharemem.User, scene *sharemem.Scene, monster *sharemem.Monster) {
	ntf := &pb.SC_SceneDataUpDate{
		SceneId:    scene.SceneId,
		SceneTag:   int32(scene.SceneTag),
		EntityList: []*pb.SceneEntityInfo{{Entity: monster.ToProto()}},
		CurSceneId: user.SceneId,
	}
	SendMsg(config.SC_SceneDataUpDate, ntf, nil, user)
}

func UserSceneGadgetNotify(user *sharemem.User, scene *sharemem.Scene, gadget *sharemem.Gadget) {
	ntf := &pb.SC_SceneDataUpDate{
		SceneId:    scene.SceneId,
		SceneTag:   int32(scene.SceneTag),
		EntityList: []*pb.SceneEntityInfo{{Entity: gadget.ToProto()}},
		CurSceneId: user.SceneId,
	}
	SendMsg(config.SC_SceneDataUpDate, ntf, nil, user)
}

func UserSceneNpcNotify(user *sharemem.User, scene *sharemem.Scene, npc *sharemem.Npc) {
	ntf := &pb.SC_SceneDataUpDate{
		SceneId:    scene.SceneId,
		SceneTag:   int32(scene.SceneTag),
		EntityList: []*pb.SceneEntityInfo{{Entity: npc.ToProto()}},
		CurSceneId: user.SceneId,
	}
	SendMsg(config.SC_SceneDataUpDate, ntf, nil, user)
}

func OnSceneDataReq(user *sharemem.User, sceneId int32, data *pb.SC_SceneDataResp) int32 {
	var scene = user.GetSceneById(sceneId)
	if scene == nil {
		return config.OBJECT_NOT_FOUND
	}
	scene.PacketSelf(data, user)
	gdconf.PacketFishPointBySceneId(sceneId, &data.EntityList)
	return config.OK
}

// ==============消息协议处理======================
// 场景

func EnterSceneReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_EnterSceneReq, new(pb.CS_EnterSceneReq), buf, user).(*pb.CS_EnterSceneReq)
	if !ok {
		return config.PROTO_ERROR
	}
	UserTeleport(user, req.SceneId, -1, buf)
	return config.OK
}

func SceneDataReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_SceneDataReq, new(pb.CS_SceneDataReq), buf, user).(*pb.CS_SceneDataReq)
	if !ok {
		return config.PROTO_ERROR
	}
	resp := pb.SC_SceneDataResp{}
	OnSceneDataReq(user, req.SceneId, &resp)
	SendMsg(config.SC_SceneDataResp, &resp, buf, user)
	return config.OK
}

func GadgetInteractReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_GadgetInteractReq, new(pb.CS_GadgetInteractReq), buf, user).(*pb.CS_GadgetInteractReq)
	if !ok {
		return config.PROTO_ERROR
	}

	var resp = pb.SC_GadgetInteractRsp{RetCode: config.OK, GadgetId: req.GadgetId, GadgetState: req.GadgetState}
	scene := user.GetSceneById(user.SceneId)
	if scene == nil {
		resp.RetCode = config.OBJECT_NOT_FOUND
		SendMsg(config.SC_GadgetInteractRsp, &resp, buf, user)
		return config.OK
	}
	gadget := user.GetSceneGadgetById(scene.SceneId, req.GadgetId)
	if gadget == nil {
		resp.RetCode = config.OBJECT_NOT_FOUND
		SendMsg(config.SC_GadgetInteractRsp, &resp, buf, user)
		return config.OK
	}
	switch pb.GadgetType(gadget.GadgetType) {
	case pb.GadgetType_GADGET_TYPE_CHEST:
		pbItemList := make([]*pb.Item, 0)
		if pb.GadgetState(gadget.GadgetState) != pb.GadgetState_GADGET_STATE_CLOSE && pb.GadgetState(req.GadgetState) == pb.GadgetState_GADGET_STATE_CLOSE {
			boxConfig := gdconf.GetGadgetActiveConfig(gadget.Id)
			if boxConfig == nil {
				resp.RetCode = config.CONFIG_NOT_FOUND
				SendMsg(config.SC_GadgetInteractRsp, &resp, buf, user)
				return config.OK
			}
			ret, itemMapOnce, _ := RewardItem(boxConfig.RewardId, nil, user)
			if ret != config.OK {
				logger.Error("reward item error, rewardId: %v, ret: %v", boxConfig.RewardId, ret)
			}
			for k, v := range itemMapOnce {
				pbItemList = append(pbItemList, &pb.Item{Id: k, Num: v})
			}
		}
		resp.ItemList = pbItemList
		gadget.GadgetState = int8(req.GadgetState)
	case pb.GadgetType_GADGET_TYPE_DAY_AND_NIGHT_CONTROLLER:
		if scene.SceneTag == 0 {
			scene.SceneTag = 1
		} else {
			scene.SceneTag = 0
		}
		gadget.GadgetState = int8(req.GadgetState)
		UserSceneGadgetNotify(user, scene, gadget)
	default:
		gadget.GadgetState = int8(req.GadgetState)
	}
	resp.GadgetState = int32(gadget.GadgetState)
	TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_GADGET_STATE, true)
	TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_SCENE_INTERACT, true, scene.SceneId, gadget.Id)
	SendMsg(config.SC_GadgetInteractRsp, &resp, buf, user)
	TriggerUnlockBox(user, gdconf.GadgetUnlockCondByOtherGadget, true, 0)
	return config.OK
}

func NpcTalkReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_NpcTalkReq, new(pb.CS_NpcTalkReq), buf, user).(*pb.CS_NpcTalkReq)
	if !ok {
		return config.PROTO_ERROR
	}

	TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_FINISH_TALK, true, req.TalkId)

	if req.ItemList != nil {
		TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_GIVE_ITEM, true, req.ItemList.Id, req.ItemList.Num)
	}

	SendMsg(config.SC_NpcTalkRsp, &pb.SC_NpcTalkRsp{RetCode: config.OK}, buf, user)
	return config.OK
}

func FinishTimelineReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_FinishTimelineReq, new(pb.CS_FinishTimelineReq), buf, user).(*pb.CS_FinishTimelineReq)
	if !ok {
		return config.PROTO_ERROR
	}

	TriggerQuest(user, sharemem.QUEST_FINISH_COND_TYPE_FINISH_PLOT, true, req.TimelineId)
	SendMsg(config.SC_FinishTimelineRsp, &pb.SC_FinishTimelineRsp{RetCode: config.OK, SceneUpdate: true}, buf, user)

	//UserSceneDataNotify(user, user.SceneId)
	return config.OK
}

func GetScenePointReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_GetScenePointReq, new(pb.CS_GetScenePointReq), buf, user).(*pb.CS_GetScenePointReq)
	if !ok {
		return config.PROTO_ERROR
	}

	scene := user.GetSceneById(req.SceneId)
	if scene == nil {
		SendMsg(config.SC_GetScenePointRsp, &pb.SC_GetScenePointRsp{RetCode: config.OBJECT_NOT_FOUND}, buf, user)
		return config.OK
	}
	unlockPointIdList := make([]int32, 0)
	for _, gadget := range user.GetSceneGadgetMap(scene.SceneId) {
		if pb.GadgetType(gadget.GadgetType) == pb.GadgetType_GADGET_TYPE_TRANSPORT_POINT || pb.GadgetType(gadget.GadgetType) == pb.GadgetType_GADGET_TYPE_BORN_POINT {
			if pb.GadgetState(gadget.GadgetState) == pb.GadgetState_GADGET_STATE_CLOSE {
				unlockPointIdList = append(unlockPointIdList, gadget.Id)
			}
		}
	}

	SendMsg(config.SC_GetScenePointRsp, &pb.SC_GetScenePointRsp{RetCode: config.OK, UnlockPointIdList: unlockPointIdList}, buf, user)
	return config.OK
}

func FishReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_FishReq, new(pb.CS_FishReq), buf, user).(*pb.CS_FishReq)
	if !ok {
		return config.PROTO_ERROR
	}

	fishPointConfig := gdconf.GetFishPointConfig(req.FishPointId)
	if fishPointConfig == nil {
		SendMsg(config.SC_FishRsp, &pb.SC_FishRsp{RetCode: config.CONFIG_NOT_FOUND}, buf, user)
		return config.OK
	}
	data, _ := tools.DeepMarshal(fishPointConfig.FishPool)
	var fishPool gdconf.IdWeightList = nil
	_ = tools.DeepUnmarshal(&fishPool, data)
	// 鱼竿和鱼饵概率加成
	fishRodConfig := gdconf.GetFishRodConfig(req.FishRodId)
	if fishRodConfig == nil {
		SendMsg(config.SC_FishRsp, &pb.SC_FishRsp{RetCode: config.CONFIG_NOT_FOUND}, buf, user)
		return config.OK
	}
	fishWeightUp(fishRodConfig.Effect, fishPool)
	fishBaitConfig := gdconf.GetFishBaitConfig(req.FishBaitId)
	if fishBaitConfig == nil {
		SendMsg(config.SC_FishRsp, &pb.SC_FishRsp{RetCode: config.CONFIG_NOT_FOUND}, buf, user)
		return config.OK
	}
	fishWeightUp(fishBaitConfig.Effect, fishPool)
	fish := sharemem.RWSRandom[*gdconf.IdWeight](fishPool)
	if fish == nil {
		logger.Error("钓鱼随机失败 %v", fishPool)
		SendMsg(config.SC_FishRsp, &pb.SC_FishRsp{RetCode: config.SERVER_ERROR}, buf, user)
		return config.OK
	}

	user.SetLastFishInfo(&sharemem.FishInfo{
		FishId:     fish.Id,
		FishRodId:  req.FishRodId,
		FishBaitId: req.FishBaitId,
	})

	SendMsg(config.SC_FishRsp, &pb.SC_FishRsp{RetCode: config.OK, FishId: fish.Id}, buf, user)
	return config.OK
}

func FishResultReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_FishResultReq, new(pb.CS_FishResultReq), buf, user).(*pb.CS_FishResultReq)
	if !ok {
		return config.PROTO_ERROR
	}

	if req.Result {
		fishInfo := user.GetLastFishInfo()
		if fishInfo == nil || fishInfo.FishId == 0 {
			logger.Error("你还没钓到鱼呢")
			SendMsg(config.SC_FishResultRsp, &pb.SC_FishResultRsp{RetCode: config.SERVER_ERROR}, buf, user)
			return config.OK
		}
		fishId := fishInfo.FishId
		fishBaitId := fishInfo.FishBaitId
		fishConfig := gdconf.GetFishConfig(fishId)
		if fishConfig == nil {
			SendMsg(config.SC_FishResultRsp, &pb.SC_FishResultRsp{RetCode: config.CONFIG_NOT_FOUND}, buf, user)
			return config.OK
		}
		ok := CostItems(map[int32]int32{fishBaitId: 1}, user)
		if !ok {
			logger.Error("道具不足 %v", fishBaitId)
			SendMsg(config.SC_FishResultRsp, &pb.SC_FishResultRsp{RetCode: config.ITEM_NOT_ENOUGH}, buf, user)
			return config.OK
		}
		length := random.GetRandomInt32(fishConfig.MinLen, fishConfig.MaxLen)
		fishInfo.FishLen = length
		ret := AddItems(map[int32]int32{fishId: 1}, user)
		if ret != config.OK {
			logger.Error("添加道具失败 %v", ret)
		}
		SendMsg(config.SC_FishResultRsp, &pb.SC_FishResultRsp{RetCode: config.OK, FishId: fishId, Length: length, ItemList: []*pb.Item{{Id: fishId, Num: 1}}}, buf, user)
	} else {
		SendMsg(config.SC_FishResultRsp, &pb.SC_FishResultRsp{RetCode: config.OK}, buf, user)
	}
	user.SetLastFishInfo(nil)

	return config.OK
}

func FishOpReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_FishOpReq, new(pb.CS_FishOpReq), buf, user).(*pb.CS_FishOpReq)
	if !ok {
		return config.PROTO_ERROR
	}

	ok = CostItems(map[int32]int32{req.FishId: 1}, user)
	if !ok {
		logger.Error("道具不足 %v", req.FishId)
		SendMsg(config.SC_FishOpRsp, &pb.SC_FishOpRsp{RetCode: config.ITEM_NOT_ENOUGH}, buf, user)
		return config.OK
	}
	pbItemList := make([]*pb.Item, 0)
	if req.Type == pb.FishOpType_FishOpTypeSell {
		itemResolveConfig := gdconf.GetItemResolveConfig(req.FishId)
		if itemResolveConfig == nil {
			SendMsg(config.SC_FishOpRsp, &pb.SC_FishOpRsp{RetCode: config.CONFIG_NOT_FOUND}, buf, user)
			return config.OK
		}
		itemMap := make(map[int32]int32)
		for _, item := range itemResolveConfig.ItemList {
			itemMap[item.ItemId] += item.ItemCount
			pbItemList = append(pbItemList, &pb.Item{
				Id:  item.ItemId,
				Num: item.ItemCount,
			})
		}
		ret := AddItems(itemMap, user)
		if ret != config.OK {
			logger.Error("添加道具失败 %v", ret)
		}
	}

	SendMsg(config.SC_FishOpRsp, &pb.SC_FishOpRsp{RetCode: config.OK, Type: req.Type, FishId: req.FishId, Length: req.Length, ItemList: pbItemList}, buf, user)

	return config.OK
}

func FishCodexReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_FishCodexReq, new(pb.CS_FishCodexReq), buf, user).(*pb.CS_FishCodexReq)
	if !ok {
		return config.PROTO_ERROR
	}
	fishPointConfig := gdconf.GetFishPointConfig(req.FishPointId)
	if fishPointConfig == nil {
		SendMsg(config.SC_FishCodexRsp, &pb.SC_FishCodexRsp{RetCode: config.CONFIG_NOT_FOUND}, buf, user)
		return config.OK
	}
	pbFishCodexList := make([]*pb.FishCodex, 0)
	totalWeight := int32(0)
	for _, idWeight := range fishPointConfig.FishPool {
		totalWeight += idWeight.Weight
	}
	for _, fishPoolItem := range fishPointConfig.FishPool {
		codexConfig := gdconf.GetCodexConfigByOtherId(fishPoolItem.Id)
		if codexConfig == nil {
			continue
		}
		pbFishCodex := &pb.FishCodex{
			FishId:   fishPoolItem.Id,
			Length:   0,
			Prob:     float32(fishPoolItem.Weight) / float32(totalWeight),
			IsUnlock: false,
		}
		fishCodex := user.GetCodexById(codexConfig.CodexId)
		if fishCodex != nil {
			pbFishCodex.Length = fishCodex.Param1
			pbFishCodex.IsUnlock = true
		}
		pbFishCodexList = append(pbFishCodexList, pbFishCodex)
	}
	SendMsg(config.SC_FishCodexRsp, &pb.SC_FishCodexRsp{RetCode: config.OK, FishCodexList: pbFishCodexList}, buf, user)
	return config.OK
}

func SceneDashFightReq(user *sharemem.User, buf *mysock.SockBuf) int16 {
	req, ok := ParseMsg(config.CS_SceneDashFightReq, new(pb.CS_SceneDashFightReq), buf, user).(*pb.CS_SceneDashFightReq)
	if !ok {
		return config.PROTO_ERROR
	}
	// 消耗冲撞次数
	var pConfig = gdconf.GetBattleGroupConfig(req.BattleGroupId)
	if pConfig == nil {
		return config.CONFIG_NOT_FOUND
	}
	costCollCount := int32(gdconf.GetConstInt("COLLISIONSREPLY"))
	if user.UserScene.CurrCollCount >= costCollCount && pConfig.GroupTag == 0 {
		user.UserScene.CurrCollCount -= costCollCount
		ret := SceneFightStart(req.BattleGroupId, user)
		if ret != config.OK {
			logger.Error("SceneFightStart error, ret: %v, uid: %v", ret, user.GetUid())
			return config.OK
		}
		ret, firstKill := SceneFightFinish(req.BattleGroupId, user)
		if ret != config.OK {
			logger.Error("SceneFightFinish error, ret: %v, uid: %v", ret, user.GetUid())
			return config.OK
		}

		var pTeam = user.GetTeam(user.GetActiveTeamId())
		var teamList = pTeam.GetActiveTeamListAll()
		trailGroupId := user.GetTrailGroupInfoBySceneId(user.SceneId)
		var trailRoleConfigs = make(map[int32]*gdconf.TrailRoleConfig)
		if trailGroupId != 0 {
			trailRoleConfigs = gdconf.GetTrailRoleConfigMap4Pos(trailGroupId)
			if trailRoleConfigs != nil {
				GetRoleExpLevel4Role(&teamList, user, trailRoleConfigs)
			}
		}

		// 发放奖励
		ret, pbItemList, roleAddExp, _ := handleBattleReward(user, req.BattleGroupId, firstKill, teamList)
		if ret != config.OK {
			logger.Error("BattleReward error, ret: %v, uid: %v", ret, user.GetUid())
			return config.OK
		}

		SendMsg(config.SC_SceneDashUpdateNtf, &pb.SC_SceneDashUpdateNtf{CurrCollCount: int64(user.UserScene.CurrCollCount)}, buf, user)
		SendMsg(config.SC_SceneDashFightRsp, &pb.SC_SceneDashFightRsp{BattleGroupId: req.BattleGroupId, ItemList: pbItemList, RoleAddExp: roleAddExp}, buf, user)
	} else {
		CreateBattle(user, buf, req.BattleGroupId, false, true, false)
	}
	return config.OK
}
